/*------------------------------------------------------------------------------
-------------------- Nano-signal-slot Simplified Unit Test ---------------------
------------------------------------------------------------------------------*/

#include <algorithm>
#include <iostream>

#include "nano_signal_slot.hpp"

/*
gcc < 4.7
g++ nano.cpp -Wall -Wextra -std=c++0x -pedantic -o ~/nano.out
gcc > 4.7
g++ nano.cpp -Wall -Wextra -std=c++11 -pedantic -o ~/nano.out
*/

struct Maximum
{
    template <typename Iterator_t>
    std::size_t operator()(Iterator_t begin, Iterator_t end)
    {
        return (*std::max_element(begin, end));
    }
};

struct Foo : public Nano::tracked
{
    std::size_t Do(std::minstd_rand& rng)
    {
        auto ret = rng();
        std::cout << __LINE__ << " <> " << ret << std::endl;
        return ret;
    }
    static std::size_t s_Do(std::minstd_rand& rng)
    {
        auto ret = rng();
        std::cout << __LINE__ << " <> " << ret << std::endl;
        return ret;
    }
};

std::size_t g_Func(std::minstd_rand& rng)
{
    auto ret = rng();
    std::cout << __LINE__ << " <> " << ret << std::endl;
    return ret;
}

int main()
{
    Foo foo;
    std::minstd_rand rng;

    // Declare a Nano::signal using function signature syntax
    Nano::signal<std::size_t(std::minstd_rand&)> signal;

    // Connect a member function to a Nano::signal
    signal.connect<Foo, &Foo::Do>(&foo);

    // Connect a static member function to a Nano::signal
    signal.connect<Foo::s_Do>();

    // Connect a free function to a Nano::signal
    signal.connect<g_Func>();

    // Emit a Nano::signal and print an SRV
    // Optional combiner template for SRV
    std::cout << "\nSignal Return Value: "
              << signal.emit<Maximum>(rng)
              << std::endl;

    // Disconnect a member function from a signal.
    // Because Foo inherits publicly from Nano::tracked,
    // Foo methods will be auto disconnected at the end of scope.
    // So the following is just for example purposes and isn't required.
    signal.disconnect<Foo, &Foo::Do>(&foo);

    // Disconnect a static member function from a signal
    signal.disconnect<Foo::s_Do>();

    // Disconnect a free function from a signal
    signal.disconnect<g_Func>();
}
